#include <QCoreApplication>
#include <QThread>
#include <QDebug>

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkProxy>
#include <QEventLoop>

#include <QDomDocument>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>

#include "QHtmlTidy.h"

QNetworkAccessManager manager;
QTextStream out(stdout);

QHtmlTidy tidy;

// https://blog.csdn.net/community/home-api/v1/get-business-list?page=3&size=20&businessType=blog&orderby=&noMore=false&year=&month=&username=mj_ww

QByteArray getRawUrlContent(QString url)
{
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36");

    QEventLoop loop;
    QNetworkReply *reply = manager.get(request);
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();

    QByteArray result = reply->readAll();

    //qInfo() << result;

    reply->deleteLater();
    return result;
}

void getPost(const QJsonObject &post)
{
    int articleId = (post["articleId"].toInt() != 0 ? post["articleId"].toInt() : post["articleid"].toString().toInt());
    QString title = post["title"].toString();
    QString description = post["description"].toString();
    QString url = post["url"].toString().left(post["url"].toString().indexOf("?"));
    QString content;

    title.remove("<em>");
    title.remove("</em>");
    description.remove("<em>");
    description.remove("</em>");

    QDomDocument doc;
    doc.setContent(tidy.parse(getRawUrlContent(url)));
    QDomNodeList list = doc.elementsByTagName("div");
    for (int i = 0; i < list.length(); i++) {
        if (list.at(i).toElement().attribute("id") == "article_content") {
            content = list.at(i).toElement().text();
            break;
        }
    }

    QSqlQuery query;
    query.prepare("INSERT INTO Blog (ID, Title, Description, Content, Url) VALUES (:ID, :Title, :Description, :Content, :Url)");
    query.bindValue(":ID", articleId);
    query.bindValue(":Title", title);
    query.bindValue(":Description", description);
    query.bindValue(":Content", content);
    query.bindValue(":Url", url);
    query.exec();
    if (query.lastError().type() == QSqlError::NoError) {
        qInfo() << "articleId: " << articleId;
    } else {
        qInfo() << query.lastError().text();
    }

    QThread::sleep(5);

}

void collectUserPosts(const QString &userName) // 不是昵称，是主页URL中的字段
{
    QString url = "https://blog.csdn.net/community/home-api/v1/get-business-list?page=%1&size=20&businessType=blog&orderby=ViewCount&noMore=false&year=&month=&username=" + userName;
    int pageCount = 1;
    int postCount = 1;
    int currentPost = 0;
    for (int i = 1; i <= pageCount; i++) {
        QJsonDocument doc = QJsonDocument::fromJson(getRawUrlContent(url.arg(i)));
        QJsonObject obj = doc.object()["data"].toObject();
        if (i == 1) {
            postCount = obj["total"].toInt();
            pageCount = postCount / 20;
            if (obj["total"].toInt() % 20 != 0) {
                pageCount += 1;
            }
        }
        for (auto item : obj["list"].toArray()) {
            QJsonObject post = item.toObject();
            getPost(post);
            currentPost += 1;
            qInfo() << QString("progress: %1 / %2").arg(currentPost).arg(postCount);
        }
    }
}

void search(const QString &query)
{
    int currentPost = 0;
    QJsonDocument doc = QJsonDocument::fromJson(getRawUrlContent("https://so.csdn.net/api/v3/search?q=" + query + "&t=all&p=1&s=0&tm=0&lv=-1&ft=0&l=&u=&ct=-1&pnt=-1&ry=-1&ss=-1&dct=-1&vco=-1&cc=-1&sc=-1&akt=-1&art=-1&ca=-1&prs=&pre=&ecc=-1&ebc=-1&urw=&ia=1&cl=-1&scl=-1&tcl=-1&platform=pc"));
    for (auto item : doc.object()["result_vos"].toArray()) {
        QJsonObject post = item.toObject();
        getPost(post);
        currentPost += 1;
        qInfo() << QString("progress: %1 / %2").arg(currentPost).arg(10);
        if (currentPost >= 10)
            break;
    }
}

// tianhai110  qq_35507234 qq_40400960  a649518776  haoyoumo u010680713 qq_43661601

int main(int argc, char **argv )
{
    QCoreApplication a(argc, argv);

    QNetworkProxy proxy(QNetworkProxy::NoProxy);
    manager.setProxy(proxy);


    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("C:\\sqlite3\\csdn.db");
    if (!db.open()) {
        qWarning() << "cannot open db: ";
    }

    QString text = R"(
                   框架是什么？
                   实际公司开发中最常用到的几个设计模式是什么？
                   阅读中的疑惑：只能理解其基础概念，实例分析的不多，实例中很难看出来设计模式。
                   spring源码分析中常用的设计模式概述，对部分代码不理解。
                   对于经典设计模式，思考在具体的应用场景中如何实践？
                   )";


    for (auto i : text.split("\n", QString::SkipEmptyParts)) {
        qInfo() << i.trimmed();
        search(i.trimmed());
    }

    db.close();

    qInfo() << "finished";

  return 0;
}
